package com.yhwch.fun.service;

import com.yhwch.fun.domain.ExecuteParam;
import com.yhwch.fun.domain.FastSegmentPojo;
import com.yhwch.fun.domain.SplitPair;
import com.yhwch.fun.utils.SplitUtil;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.util.CollectionUtils;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public abstract class ImportDataFromFileAbstract<T> {

    abstract int insert(T param);

    abstract T select(Map<String,Object> param);

    abstract Map<String,Object> genSelectParam(T t);

    abstract T parseT(String t);

    abstract ExecuteParam getExecuteParam();

    /**
     * 自动对区间文件进行划分
     * @param start 开始序号
     * @param end 结束需要
     * @param splitCount 将区间分隔为几块
     * @param useSelect 是否使用查询 如果存在则不执行插入，一般是二次校验数据时使用
     */
    public String autoSplitTask(int start,int end,int splitCount,int useSelect){
        List<SplitPair> list = SplitUtil.computeTableShardIntervalPair(start,end,splitCount);
        if(CollectionUtils.isEmpty(list)){
            System.out.println("分隔失败");
        }
        //多线程并行执行任务
        ExecutorService pool = Executors.newFixedThreadPool(list.size());
        for (int i = 0; i <list.size() ; i++) {
            SplitPair pair = list.get(i);
            pool.execute(()->{
                readFileAndWriteData(pair.getBegin(),pair.getEnd(),useSelect);
            });
        }
        return "任务全部提交"+list.toString();
    }

    public void segmentFile(){
        ExecuteParam executeParam = this.getExecuteParam();
        boolean isExecute = executeParam.getTaskExecService().isExecute(executeParam.getKeyName(),"split");
        if(!isExecute){
            System.out.println("当前批次已被执行，或被占用，不重复执行split");
            return;
        }
        FastSegmentPojo fastSegmentPojo = new FastSegmentPojo();
        fastSegmentPojo.setSegmetnFileSuffix(executeParam.getFileNameSuffix());
        fastSegmentPojo.setSegmentFilePreName(executeParam.getPath()+executeParam.getChildFileName());
        fastSegmentPojo.setBlockFileSize(executeParam.getChildFileSize());
        fastSegmentPojo.setFilePath(executeParam.getPath()+executeParam.getFatherFileName());
        fastSegmentPojo.setPoolSize(5);
        fastSegmentPojo.setCharSet(executeParam.getCharsetName());

        /**
         * reg与split组合字段  用于验证分隔后文件首尾内容是否完整，不完整则对内容进行调整
         * reg不为空优先使用正则
         */
        //reg
        fastSegmentPojo.setRegStrForRow("");
        // split splitStr、splitSize组合使用
        fastSegmentPojo.setSplitStr(executeParam.getSplitStr()); //分隔符
        fastSegmentPojo.setSplitSize(executeParam.getSplitCount()); //分隔后的长度
        FastSegmentFile.doSegmentFile(fastSegmentPojo);
    }

    /**
     * 读取文件并写入数据
     * @param start
     * @param end
     * @param useSelect
     */
    public void readFileAndWriteData(int start,int end,int useSelect){
        int suc = 0;
        int fail = 0;
        int select = 0;
        try {
            ExecuteParam executeParam = this.getExecuteParam();
            for (int i = start; i < end ; i++) {
                boolean isExecute = executeParam.getTaskExecService().isExecute(executeParam.getKeyName(),String.valueOf(i));
                if(!isExecute){
                    System.out.println("序列【"+i+"】当前批次已被执行，或被占用，不重复执行");
                    continue;
                }
                //先FileReader把文件读出来再bufferReader按行读  reader.readLine(); 没有标题用不着了
                BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(executeParam.getPath() + executeParam.getChildFileName()
                        +String.valueOf(i) + executeParam.getFileNameSuffix()),executeParam.getCharsetName()));
                String line = null;
                while ((line = reader.readLine()) != null ) {
                    try {
                        T t = this.parseT(line);

                        if(useSelect == 1){
                            T t1 = this.select(this.genSelectParam(t));
                            if(t1 != null){
                                select++;
                                System.out.println("序列【"+i+"】已存在"+select);
                                continue;
                            }
                        }
                        long s = System.currentTimeMillis();
                        this.insert(t);
                        long e = System.currentTimeMillis();
                        System.out.println("序列【"+i+"】耗时：" + (e - s));
                        suc++;
                    }catch (DuplicateKeyException e1){
                        System.out.println("序列【"+i+"】主键冲突:"+line);
                    }catch (Exception xx){
                        fail++;
                        System.out.println("序列【"+i+"】异常"+xx.getMessage());
                        System.out.println("序列【"+i+"】错误数据:"+line);
                    }
                }
                reader.close();
            }
        } catch (Exception ex) {
            //在命令行打印异常信息在程序中出错的位置及原因。
            ex.printStackTrace();
        }
        System.out.println("序列【"+start+"-"+end+"】执行完毕,suc【"+suc+"】,fail【"+fail+"】");
    }
}
